﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace HeyPiPi_Desk.Tools
{
    public static class AESEncryption
    {
        #region 变量
        /// <summary>
        /// 一次处理的明文字节数
        /// </summary>
        //private static readonly int encryptSize = 10000000;
        /// <summary>
        /// 一次处理的密文字节数
        /// </summary>
        //private static readonly int decryptSize = 10000016;
        //默认密钥向量   
        private static byte[] _key1 = { 0x12, 0x74, 0x46, 0x73, 0x60, 0xAC, 0xDD, 0xAF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
        #endregion

        #region 加密字符串
        /// <summary>  
        /// AES加密字符串
        /// </summary>  
        /// <param name="plainText">明文字符串</param>  
        /// <param name="strKey">密钥(16位字母或数字)</param>  
        /// <returns>返回加密后的密文字符串</returns>  
        public static string AESEncrypt(string plainText, string strKey = "1234567891234567")
        {
            //分组加密算法  
            SymmetricAlgorithm des = Rijndael.Create();
            byte[] inputByteArray = Encoding.UTF8.GetBytes( plainText );//得到需要加密的字节数组      
            des.Mode = CipherMode.CFB;
            des.Padding = PaddingMode.Zeros;
            des.Key = Encoding.UTF8.GetBytes( strKey );//设置密钥及密钥向量 
            des.IV = _key1;
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream( ms, des.CreateEncryptor(), CryptoStreamMode.Write );
            cs.Write( inputByteArray, 0, inputByteArray.Length );
            cs.FlushFinalBlock();
            byte[] cipherBytes = ms.ToArray();//得到加密后的字节数组  
            cs.Close();
            ms.Close();

            return Convert.ToBase64String( cipherBytes );
        }
        #endregion

        #region 解密字符串
        /// <summary>  
        /// AES解密  字符串
        /// </summary>  
        /// <param name="cipherText">密文字节数组</param>  
        /// <param name="strKey">密钥(16位字母或数字)</param>  
        /// <returns>返回解密后的字符串</returns>  
        public static string AESDecrypt(byte[] cipherText, string strKey = "1234567891234567")
        {
            SymmetricAlgorithm des = Rijndael.Create();
            des.Mode = CipherMode.CFB;
            des.Padding = PaddingMode.Zeros;
            des.Key = Encoding.UTF8.GetBytes( strKey );
            des.IV = _key1;
            byte[] decryptBytes = new byte[ cipherText.Length ];
            MemoryStream ms = new MemoryStream( cipherText );
            CryptoStream cs = new CryptoStream( ms, des.CreateDecryptor(), CryptoStreamMode.Read );
            cs.Read( decryptBytes, 0, decryptBytes.Length );
            cs.Close();
            ms.Close();
            return Encoding.UTF8.GetString( decryptBytes ).ToString().Replace( "\0", null );
        }
        #endregion

        #region 加密字节数组
        /// <summary>
        /// AES 加密(高级加密标准，是下一代的加密算法标准，速度快，安全级别高，目前 AES 标准的一个实现是 Rijndael 算法)
        /// </summary>
        /// <param name="EncryptByte">字节数组</param>
        /// <param name="EncryptKey">加密密钥</param>
        public static byte[] AESEncrypt(byte[] EncryptByte, string EncryptKey)
        {
            if (EncryptByte.Length == 0) { throw ( new Exception( "明文不得为空" ) ); }
            if (string.IsNullOrWhiteSpace( EncryptKey )) { throw ( new Exception( "密钥不得为空" ) ); }

            byte[] m_strEncrypt;
            byte[] m_btIV = _key1;
            //byte[] m_salt = Convert.FromBase64String("gsf4jvkyhye5/d7k8OrLgM==");
            byte[] m_salt = _key1;
            Rijndael m_AESProvider = Rijndael.Create();
            m_AESProvider.Mode = CipherMode.CFB;
            m_AESProvider.Padding = PaddingMode.Zeros;
            try
            {
                MemoryStream m_stream = new MemoryStream();
                PasswordDeriveBytes pdb = new PasswordDeriveBytes( EncryptKey, m_salt );
                ICryptoTransform transform = m_AESProvider.CreateEncryptor( pdb.GetBytes( 32 ), m_btIV );
                CryptoStream m_csstream = new CryptoStream( m_stream, transform, CryptoStreamMode.Write );
                m_csstream.Write( EncryptByte, 0, EncryptByte.Length );
                m_csstream.FlushFinalBlock();
                m_strEncrypt = m_stream.ToArray();
                m_stream.Close(); m_stream.Dispose();
                m_csstream.Close(); m_csstream.Dispose();
            }
            catch (IOException ex) { throw ex; }
            catch (CryptographicException ex) { throw ex; }
            catch (ArgumentException ex) { throw ex; }
            catch (Exception ex) { throw ex; }
            finally { m_AESProvider.Clear(); }
            return m_strEncrypt;
        }
        #endregion

        #region 解密字节数组
        /// <summary>
        /// AES 解密(高级加密标准，是下一代的加密算法标准，速度快，安全级别高，目前 AES 标准的一个实现是 Rijndael 算法)
        /// </summary>
        /// <param name="DecryptByte">密钥向量</param>
        /// <param name="DecryptKey">解密密钥</param>
        public static byte[] AESDecryptByte(byte[] DecryptByte, string DecryptKey)
        {
            if (DecryptByte.Length == 0) { throw ( new Exception( "密文不得为空" ) ); }
            if (string.IsNullOrWhiteSpace( DecryptKey )) { throw ( new Exception( "密钥不得为空" ) ); }
            byte[] m_strDecrypt;
            byte[] m_btIV = _key1;
            //byte[] m_salt = Convert.FromBase64String("gsf4jvkyhye5/d7k8OrLgM==");
            byte[] m_salt = _key1;
            Rijndael m_AESProvider = Rijndael.Create();
            m_AESProvider.Mode = CipherMode.CFB;
            m_AESProvider.Padding = PaddingMode.Zeros;
            try
            {
                MemoryStream m_stream = new MemoryStream();
                PasswordDeriveBytes pdb = new PasswordDeriveBytes( DecryptKey, m_salt );
                ICryptoTransform transform = m_AESProvider.CreateDecryptor( pdb.GetBytes( 32 ), m_btIV );
                CryptoStream m_csstream = new CryptoStream( m_stream, transform, CryptoStreamMode.Write );
                m_csstream.Write( DecryptByte, 0, DecryptByte.Length );
                m_csstream.FlushFinalBlock();
                m_strDecrypt = m_stream.ToArray();
                m_stream.Close(); m_stream.Dispose();
                m_csstream.Close(); m_csstream.Dispose();
            }
            catch (IOException ex) { throw ex; }
            catch (CryptographicException ex) { throw ex; }
            catch (ArgumentException ex) { throw ex; }
            catch (Exception ex) { throw ex; }
            finally { m_AESProvider.Clear(); }
            return m_strDecrypt;
        }
        #endregion

        #region 加密文件
        /// <summary>
        /// 加密文件
        /// </summary>
        public static void EncryptFile(string path, string pwd="1234567891234567")
        {
            //try
            //{
            //    try
            //    {
            //        if (!File.Exists( path + ".temp" ))
            //        {
            //            File.Create( path + ".temp" ).Close();
            //        }
            //    }
            //    catch { }
            //    using (FileStream fs = new FileStream( path, FileMode.Open, FileAccess.ReadWrite ))
            //    {
            //        if (fs.Length > 0)
            //        {
            //            try
            //            {
            //                if (!File.Exists( path + ".temp" ))
            //                {
            //                    File.Create( path + ".temp" ).Close();
            //                }
            //            }
            //            catch { }
            //            using (FileStream fsnew = new FileStream( path + ".temp", FileMode.OpenOrCreate, FileAccess.ReadWrite ))
            //            {
            //                if (File.Exists( path + ".temp" )) File.SetAttributes( path + ".temp", FileAttributes.Archive );
            //                int blockCount = ( (int)fs.Length - 1 ) / encryptSize + 1;
            //                for (int i = 0; i < blockCount; i++)
            //                {
            //                    int size = encryptSize;
            //                    if (i == blockCount - 1) size = (int)( fs.Length - i * encryptSize );
            //                    byte[] bArr = new byte[ size ];
            //                    fs.Read( bArr, 0, size );
            //                    byte[] result = AESEncrypt( bArr, pwd );
            //                    fsnew.Write( result, 0, result.Length );
            //                    fsnew.Flush();
            //                }
            //                fsnew.Close();
            //                fsnew.Dispose();

            //                fs.Close();
            //                fs.Dispose();
            //                FileAttributes fileAttr = File.GetAttributes( path );
            //                File.SetAttributes( path, FileAttributes.Archive );
            //                try
            //                {
            //                    File.Delete( path );
            //                }
            //                catch { }
            //                if (File.Exists( path ))
            //                {
            //                    try
            //                    {
            //                        File.Delete( path );
            //                    }
            //                    catch { }
            //                    File.Copy( path + ".temp", path, true );
            //                }
            //                else
            //                {
            //                    File.Move( path + ".temp", path );
            //                }

            //                File.SetAttributes( path, fileAttr );
            //            }


            //        }
            //    }
            //}
            //catch (Exception ex)
            //{
            //    File.Delete( path + ".temp" );
            //    throw ex;
            //}
        }
        #endregion

        #region 解密文件
        /// <summary>
        /// 解密文件
        /// </summary>
        public static void DecryptFile(string path,string pwd = "1234567891234567")
        {
            //try
            //{
            //    try
            //    {
            //        if (!File.Exists( path + ".temp" ))
            //        {
            //            File.Create( path + ".temp" ).Close();
            //        }
            //    }
            //    catch { }
            //    using (FileStream fs = new FileStream( path, FileMode.Open, FileAccess.ReadWrite ))
            //    {
            //        if (fs.Length > 0)
            //        {
            //            try
            //            {
            //                if (!File.Exists( path + ".temp" ))
            //                {
            //                    File.Create( path + ".temp" ).Close();
            //                }
            //            }
            //            catch { }
            //            using (FileStream fsnew = new FileStream( path + ".temp", FileMode.OpenOrCreate, FileAccess.ReadWrite ))
            //            {
            //                if (File.Exists( path + ".temp" )) File.SetAttributes( path + ".temp", FileAttributes.Archive );
            //                int blockCount = ( (int)fs.Length - 1 ) / decryptSize + 1;
            //                for (int i = 0; i < blockCount; i++)
            //                {
            //                    int size = decryptSize;
            //                    if (i == blockCount - 1) size = (int)( fs.Length - i * decryptSize );
            //                    byte[] bArr = new byte[ size ];
            //                    fs.Read( bArr, 0, size );
            //                    byte[] result = AESDecryptByte( bArr, pwd );
            //                    fsnew.Write( result, 0, result.Length );
            //                    fsnew.Flush();
            //                }
            //                fsnew.Close();
            //                fsnew.Dispose();
            //            }
            //        }
            //        fs.Close();
            //        fs.Dispose();
            //        FileAttributes fileAttr = File.GetAttributes( path );
            //        File.SetAttributes( path, FileAttributes.Archive );
            //        try
            //        {
            //            File.Delete( path );
            //        }
            //        catch { }
            //        if (File.Exists( path ))
            //        {
            //            try
            //            {
            //                File.Delete( path );
            //            }
            //            catch { }
            //            File.Copy( path + ".temp", path, true );
            //        }
            //        else
            //        {
            //            File.Move( path + ".temp", path );
            //        }
            //        File.SetAttributes( path, fileAttr );
            //    }
            //}
            //catch (Exception ex)
            //{
            //    File.Delete( path + ".temp" );
            //    throw ex;
            //}
        }
        #endregion
    }
}
